/*------------------------------------------------------------------------------
$module:      MemBlock
$package:     CseApi
$purpose:     TMemBlock class definition
$author:      WAYNE WORK STDIO
$CreateAt:    08/12/15
$LastModify:
$license:     Mozilla Public License Version 1.1
------------------------------------------------------------------------------*/

#include "CseApi_.h"

// Define TAbsStream
//==============================================================================
TBool TAbsStream::isEnd(size_t position)
{
    return true;
}

size_t TAbsStream::seek(int offset, int origin)
{
    return 0;
}

size_t TAbsStream::tell()
{
    return 0;
}

size_t TAbsStream::read(char *buffer, size_t count)
{
    return 0;
}

size_t TAbsStream::write(const char *buffer, size_t count)
{
    return 0;
}

void TAbsStream::flush()
{
}

// Define TMemAbsStream
//==============================================================================
char *TMemAbsStream::addr()
{
    return NULL;
}

int TMemAbsStream::len()
{
    return 0;
}

// Define TFixedStream
//==============================================================================
TFixedStream::TFixedStream()
{
    m_data = NULL;
    m_position = 0;
    m_length = 0;
}

TFixedStream::TFixedStream(char *buff, size_t iLen)
{
    m_data = buff;
    m_position = 0;
    m_length = iLen;
}

TFixedStream::~TFixedStream()
{
}

TFixedStream& TFixedStream::operator=(const TFixedStream& stream)
{
    m_data = stream.m_data;
    m_position = stream.m_position ;
    m_length = stream.m_length;
    return *this;
}

char *TFixedStream::addr()
{
    return m_data;
}

int TFixedStream::len()
{
    return m_length;
}

TBool TFixedStream::isEnd(size_t position)
{
    return position >= m_length;
}

size_t TFixedStream::seek(int offset, int origin)
{
    if (origin == SEEK_SET)               // from beginning
        m_position = offset;
    else if (origin == SEEK_CUR)          // offset by current
        m_position += offset;
    else m_position = m_length - offset;  // offset by end

    if (m_position >= m_length)
        m_position = m_length;
    else if (m_position < 0) m_position = 0;
    return m_position;
}

size_t TFixedStream::tell()
{
    return m_position;
}

size_t TFixedStream::read(char *buffer, size_t count)
{
    if (m_length - m_position < count)
        throw LOG_CSE_ERR(CSE_RANGE_ERR,_T("access memory stream out of range"));

    char *sour = m_data + m_position;
    for (size_t i=0; i < count; i++,buffer++,sour++)
        *buffer = *sour;
    m_position += count;

    return count;
}

size_t TFixedStream::write(const char *buffer, size_t count)
{
    size_t iNewSize = m_position + count;
    if (iNewSize > m_length)
        throw LOG_CSE_ERR(CSE_RANGE_ERR,_T("access memory stream out of range"));

    // next write to buff
    char *pTarg = m_data + m_position;
    for (size_t i=0; i < count; i++,buffer++,pTarg++)
        *pTarg = *buffer;
    m_position += count;

    return count;
}

// Define TSizedStream
//==============================================================================
TSizedStream::TSizedStream()
{
    m_data = new TIntArray();
    m_position = 0;
    m_length = 0;
}

TSizedStream::TSizedStream(const TCharArray& str)
{
    size_t iStrLen = str.len() * sizeof(TXchar);
    size_t iSize = iStrLen + sizeof(TXchar);   // include last '\0'
    m_data = new TIntArray(iSize / sizeof(TInt) + 1);

    char *sour = (char *) str.addr();
    char *targ = (char *) m_data->addr();
    for (size_t i=0; i < iSize; i++,targ++,sour++)
        *targ = *sour;

    m_position = 0;
    m_length = iStrLen;
}

TSizedStream::~TSizedStream()
{
    delete m_data;
}

void TSizedStream::resize(int iNewSize)
{
    ASSERT_TRUE(iNewSize >= 0);
    if ((size_t)iNewSize > m_length)
    {
        size_t iNew = ((size_t)iNewSize - m_length) / sizeof(TInt) + 1;
        for (size_t i = 0; i < iNew; i++)
            m_data->append(0);
    }
    else if (iNewSize == 0)
    {
        delete m_data;
        m_data = new TIntArray();
    }

    m_length = iNewSize;
    if (m_position > m_length) m_position = m_length;
}

char *TSizedStream::addr()
{
    return (char *) m_data->addr();
}

int TSizedStream::len()
{
    return m_length;
}

TBool TSizedStream::isEnd(size_t position)
{
    return position >= m_length;
}

size_t TSizedStream::seek(int offset, int origin)
{
    if (origin == SEEK_SET)               // from beginning
        m_position = offset;
    else if (origin == SEEK_CUR)          // offset by current
        m_position += offset;
    else m_position = m_length - offset;  // offset by end

    if (m_position >= m_length)
        m_position = m_length;
    else if (m_position < 0) m_position = 0;
    return m_position;
}

size_t TSizedStream::tell()
{
    return m_position;
}

size_t TSizedStream::read(char *buffer, size_t count)
{
    if (m_length - m_position < count)
        throw LOG_CSE_ERR(CSE_RANGE_ERR,_T("access memory stream out of range"));

    char *sour = (char *)m_data->addr() + m_position;
    for (size_t i=0; i < count; i++,buffer++,sour++)
        *buffer = *sour;
    m_position += count;

    return count;
}

size_t TSizedStream::write(const char *buffer, size_t count)
{
    size_t iNewSize = m_position + count;

    // first try enlarge to enough space
    if (iNewSize > m_length)
    {
        size_t iNew = (iNewSize - m_length) / sizeof(TInt) + 1;
        for (size_t i = 0; i < iNew; i++)
            m_data->append(0);
        m_length = iNewSize;
    }

    // next write to buff
    char *pTarg = (char *)m_data->addr() + m_position;
    for (size_t i=0; i < count; i++,buffer++,pTarg++)
        *pTarg = *buffer;
    m_position += count;

    return count;
}

// Define TMemBlock
//==============================================================================
TMemBlock::TMemBlock()
{
    m_data = NULL;
}

TMemBlock::TMemBlock(int iSize)
{
    if (iSize <= 0)
        m_data = NULL;
    else m_data = new TChar[iSize];
}

TMemBlock::TMemBlock(int MagicNum, TMemBlock& block)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = block.transfer(NULL);
}

TMemBlock::TMemBlock(TChar *addr)
{
    m_data = addr;
}

TMemBlock::~TMemBlock()
{
    if (m_data != NULL)
        delete []m_data;
}

TMemBlock::TMemBlock(TFixedStream& stream, int iSize)
{
    if (iSize <= 0)
        m_data = NULL;
    else m_data = new char[iSize];
    stream = TFixedStream(m_data,iSize);
}

TMemBlock::operator TChar*() const
{
    return m_data;
}

TChar& TMemBlock::operator[](int index) const
{   // no range checking, should provided at inherited class
    return m_data[index];
}

TMemBlock TMemBlock::slice(int index, int iLen) const
{
    if (iLen <= 0)
        return (TChar *) NULL;
    else
    {
        TChar *mem = new TChar[iLen];
        
        TChar *pSour = m_data + index;
        TChar *pTarg = mem;
        for (int i = 0; i < iLen; i++, pSour++, pTarg++)
            *pTarg = *pSour;  // no range checking
            
        return mem;
    }
}

TBool TMemBlock::isEmpty() const
{
    return m_data == NULL;
}

TChar *TMemBlock::addr() const
{
    return m_data;
}

TChar *TMemBlock::transfer(TChar *pOther)
{
    TChar *ret = m_data;
    m_data = pOther;
    return ret;
}

// Define TUniMemBlock
//==============================================================================
TUniMemBlock::TUniMemBlock()
{
    m_data = NULL;
}

TUniMemBlock::TUniMemBlock(int iSize)
{
    if (iSize <= 0)
        m_data = NULL;
    else m_data = new TWchar[iSize];
}

TUniMemBlock::TUniMemBlock(int MagicNum, TUniMemBlock& block)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = block.transfer(NULL);
}

TUniMemBlock::TUniMemBlock(TWchar *addr)
{
    m_data = addr;
}

TUniMemBlock::~TUniMemBlock()
{
    if (m_data != NULL)
        delete []m_data;
}

TUniMemBlock::TUniMemBlock(TFixedStream& stream, int iSize)
{
    m_data = new TWchar[iSize];
    stream = TFixedStream((TChar *)m_data,iSize * sizeof(TWchar));
}

TUniMemBlock::operator TWchar*() const
{
    return m_data;
}

TWchar& TUniMemBlock::operator[](int index) const
{   // no range checking, should provided at inherited class
    return m_data[index];
}

TUniMemBlock TUniMemBlock::slice(int index, int iLen) const
{
    if (iLen <= 0)
        return (TWchar *) NULL;
    else
    {
        TWchar *mem = new TWchar[iLen];
        
        TWchar *pSour = m_data + index;
        TWchar *pTarg = mem;
        for (int i = 0; i < iLen; i++, pSour++, pTarg++)
            *pTarg = *pSour;  // no range checking
            
        return mem;
    }
}

TBool TUniMemBlock::isEmpty() const
{
    return m_data == NULL;
}

TWchar *TUniMemBlock::addr() const
{
    return m_data;
}

TWchar *TUniMemBlock::transfer(TWchar *pOther)
{
    TWchar *ret = m_data;
    m_data = pOther;
    return ret;
}
